<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>钠水反应爆炸模拟</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #000;
        }
        #info {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            background: rgba(0, 0, 0, 0.7);
            padding: 10px;
            border-radius: 5px;
            font-family: Arial, sans-serif;
        }
        #start-btn {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 15px 30px;
            background: #ff6600;
            color: white;
            border: none;
            border-radius: 5px;
            font-size: 18px;
            cursor: pointer;
            z-index: 100;
            box-shadow: 0 0 20px #ff6600;
        }
        #start-btn:hover {
            background: #ff8800;
            box-shadow: 0 0 30px #ff8800;
        }
    </style>
</head>
<body>
    <div id="info">钠与水反应爆炸模拟 | 点击开始按钮观看</div>
    <button id="start-btn">开始爆炸反应</button>
    
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
    <script>
        // 初始化场景
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x000000);
        
        // 初始化相机
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 5, 20);
        
        // 初始化渲染器
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.body.appendChild(renderer.domElement);
        
        // 添加轨道控制器
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        
        // 添加光源
        const ambientLight = new THREE.AmbientLight(0x404040);
        scene.add(ambientLight);
        
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(5, 10, 7);
        directionalLight.castShadow = true;
        directionalLight.shadow.mapSize.width = 2048;
        directionalLight.shadow.mapSize.height = 2048;
        scene.add(directionalLight);
        
        // 创建水面
        const waterGeometry = new THREE.CylinderGeometry(5, 5, 0.5, 32);
        const waterMaterial = new THREE.MeshPhongMaterial({
            color: 0x3399ff,
            transparent: true,
            opacity: 0.8,
            specular: 0x111111,
            shininess: 30
        });
        const water = new THREE.Mesh(waterGeometry, waterMaterial);
        water.position.y = -1;
        water.rotation.x = Math.PI / 2;
        water.receiveShadow = true;
        scene.add(water);
        
        // 创建钠球
        const sodiumGeometry = new THREE.SphereGeometry(0.5, 32, 32);
        const sodiumMaterial = new THREE.MeshPhongMaterial({
            color: 0x6666ff,
            specular: 0x111111,
            shininess: 30,
            emissive: 0x4444ff,
            emissiveIntensity: 0.2
        });
        const sodium = new THREE.Mesh(sodiumGeometry, sodiumMaterial);
        sodium.position.set(0, 2, 0);
        sodium.castShadow = true;
        scene.add(sodium);
        
        // 爆炸粒子系统
        let particles = [];
        let explosion = false;
        let explosionTime = 0;
        let explosionSound;
        
        // 音频加载器
        const audioLoader = new THREE.AudioLoader();
        const listener = new THREE.AudioListener();
        camera.add(listener);
        
        // 加载爆炸声音
        audioLoader.load('https://assets.mixkit.co/sfx/preview/mixkit-explosion-impact-1684.mp3', function(buffer) {
            explosionSound = new THREE.Audio(listener);
            explosionSound.setBuffer(buffer);
            explosionSound.setLoop(false);
            explosionSound.setVolume(1.0);
        });
        
        // 创建爆炸粒子
        function createExplosion() {
            const particleCount = 500;
            const particleGeometry = new THREE.BufferGeometry();
            const positions = new Float32Array(particleCount * 3);
            const colors = new Float32Array(particleCount * 3);
            const sizes = new Float32Array(particleCount);
            
            for (let i = 0; i < particleCount; i++) {
                // 随机位置
                const angle = Math.random() * Math.PI * 2;
                const speed = Math.random() * 1.5 + 0.5;
                
                positions[i * 3] = Math.cos(angle) * speed;
                positions[i * 3 + 1] = Math.random() * speed;
                positions[i * 3 + 2] = Math.sin(angle) * speed;
                
                // 随机颜色 (钠反应会产生黄色/橙色火焰)
                colors[i * 3] = Math.random() > 0.3 ? 1 : 0.8; // R
                colors[i * 3 + 1] = Math.random() > 0.7 ? 0.3 : 0.6; // G
                colors[i * 3 + 2] = 0.1; // B
                
                // 随机大小
                sizes[i] = Math.random() * 0.3 + 0.1;
            }
            
            particleGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            particleGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
            particleGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
            
            const particleMaterial = new THREE.PointsMaterial({
                size: 0.3,
                vertexColors: true,
                transparent: true,
                opacity: 0.9,
                blending: THREE.AdditiveBlending,
                sizeAttenuation: true
            });
            
            const particleSystem = new THREE.Points(particleGeometry, particleMaterial);
            particleSystem.position.copy(sodium.position);
            scene.add(particleSystem);
            
            return {
                system: particleSystem,
                positions: positions,
                velocities: Array.from({ length: particleCount }, () => ({
                    x: (Math.random() - 0.5) * 1.5,
                    y: Math.random() * 1.5,
                    z: (Math.random() - 0.5) * 1.5
                })),
                lifetimes: Array.from({ length: particleCount }, () => Math.random() * 3 + 1)
            };
        }
        
        // 创建爆炸冲击波
        function createShockwave() {
            const geometry = new THREE.RingGeometry(0.1, 5, 32);
            const material = new THREE.MeshBasicMaterial({
                color: 0xff8800,
                side: THREE.DoubleSide,
                transparent: true,
                opacity: 0.8
            });
            const ring = new THREE.Mesh(geometry, material);
            ring.position.copy(sodium.position);
            ring.rotation.x = Math.PI / 2;
            scene.add(ring);
            
            return {
                mesh: ring,
                scale: 0.1,
                opacity: 0.8
            };
        }
        
        // 开始按钮事件
        document.getElementById('start-btn').addEventListener('click', function() {
            this.style.display = 'none';
            startReaction();
        });
        
        // 开始反应
        function startReaction() {
            // 钠球下落动画
            const sodiumFall = {
                startY: sodium.position.y,
                endY: water.position.y + 0.3,
                duration: 2,
                time: 0
            };
            
            let shockwave = null;
            
            // 动画循环
            function animateReaction() {
                // 钠球下落
                if (sodiumFall.time < sodiumFall.duration) {
                    sodiumFall.time += 0.016;
                    const progress = sodiumFall.time / sodiumFall.duration;
                    sodium.position.y = sodiumFall.startY - (sodiumFall.startY - sodiumFall.endY) * progress;
                    
                    // 钠球接触水面时开始爆炸
                    if (progress > 0.9 && !explosion) {
                        explosion = true;
                        particles = createExplosion();
                        shockwave = createShockwave();
                        scene.remove(sodium);
                        
                        // 播放爆炸声音
                        if (explosionSound) {
                            explosionSound.play();
                        }
                        
                        // 添加爆炸光效
                        const explosionLight = new THREE.PointLight(0xffaa00, 10, 20);
                        explosionLight.position.copy(sodium.position);
                        scene.add(explosionLight);
                        
                        // 光效衰减
                        const lightDecay = setInterval(() => {
                            explosionLight.intensity *= 0.9;
                            if (explosionLight.intensity < 0.1) {
                                clearInterval(lightDecay);
                                scene.remove(explosionLight);
                            }
                        }, 100);
                    }
                }
                
                // 爆炸粒子效果
                if (explosion) {
                    explosionTime += 0.016;
                    
                    // 更新粒子系统
                    const geometry = particles.system.geometry;
                    const positions = geometry.attributes.position.array;
                    const originalPositions = particles.positions;
                    
                    for (let i = 0; i < particles.positions.length / 3; i++) {
                        if (particles.lifetimes[i] > 0) {
                            particles.lifetimes[i] -= 0.016;
                            
                            positions[i * 3] += particles.velocities[i].x;
                            positions[i * 3 + 1] += particles.velocities[i].y;
                            positions[i * 3 + 2] += particles.velocities[i].z;
                            
                            // 粒子减速
                            particles.velocities[i].x *= 0.96;
                            particles.velocities[i].y *= 0.96;
                            particles.velocities[i].z *= 0.96;
                            
                            // 粒子受重力影响
                            particles.velocities[i].y -= 0.02;
                        } else {
                            // 粒子生命周期结束
                            positions[i * 3] = originalPositions[i * 3];
                            positions[i * 3 + 1] = originalPositions[i * 3 + 1];
                            positions[i * 3 + 2] = originalPositions[i * 3 + 2];
                            particles.lifetimes[i] = Math.random() * 2 + 1;
                        }
                    }
                    
                    geometry.attributes.position.needsUpdate = true;
                    
                    // 更新冲击波
                    if (shockwave) {
                        shockwave.scale += 0.1;
                        shockwave.opacity *= 0.95;
                        shockwave.mesh.scale.set(shockwave.scale, shockwave.scale, shockwave.scale);
                        shockwave.mesh.material.opacity = shockwave.opacity;
                        
                        if (shockwave.opacity < 0.05) {
                            scene.remove(shockwave.mesh);
                            shockwave = null;
                        }
                    }
                    
                    // 爆炸结束后移除粒子系统
                    if (explosionTime > 8) {
                        scene.remove(particles.system);
                        explosion = false;
                    }
                }
                
                controls.update();
                renderer.render(scene, camera);
                requestAnimationFrame(animateReaction);
            }
            
            animateReaction();
        }
        
        // 窗口大小调整
        window.addEventListener('resize', function() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
        
        // 初始渲染
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }
        
        animate();
    </script>
</body>
</html>
